import PluginBase from "./PluginBase.js";
import World3dEvent from "../scene/event/World3dEvent.js";
import * as THREE from "../../../modules/three/three.module.js";
import UndoType from "../scene/undo/UndoType.js";
import {KeyboardState, mapColorCssToCode} from "../lib/CommonConsts.js";
import {arrAsubB, removeArrayItem} from "../lib/util/ToolMethods.js";
import ClipperTool from "../lib/clipper_js/ClipperTool.js";
import WorkArea from "../model/WorkArea.js";

const axesHelper = new THREE.AxesHelper(20)
const matRot = new THREE.Matrix4();

/**
 * @param {WorkArea} minuend 作为被减数的工作区
 * @param {WorkArea[]} subtrahends 若干个作为减数的工作区
 * @return {WorkArea[]}
 */
function createAreasBySubtraction(minuend, subtrahends) {
  const subVerts = [minuend.verts]
  subtrahends.forEach(area => {
    const pts = area.verts[0].map(it => {
      const v = new THREE.Vector3(it.x, it.y, 0)
      v.applyMatrix4(area.planeMat).applyMatrix4(minuend.planeMatInv)
      return {x: v.x, y: v.y}
    })
    const vert = [pts, area.verts[1]]
    subVerts.push(vert)
  })
  const vertsLst = ClipperTool.polygonsSub(subVerts)
  const target = []
  vertsLst.forEach(verts => {
    const vo = new WorkArea().copyWithNoVerts(minuend)
    vo.verts = verts
    vo.updateLocalBox()
    target.push(vo)
  })
  return target
}
export default class SelectWorkAreaPlugin extends PluginBase {
  /**
   * @type {WorkAreaMesh[]}
   */
  areaMeshes = []
  world3d

  constructor(world3d) {
    super()
    this.world3d = world3d
  }
  get areaMesh() {
    if (!this.areaMeshes.length) {
      return null
    }
    return this.areaMeshes[this.areaMeshes.length - 1]
  }
  /**
   * 选中多个工作区时，最后一个选中的做为被减对象，其余的做为减数
   * @return {WorkArea[]}
   */
  createAreaMeshesBySelections() {
    if (this.areaMeshes.length <= 1) {
      return this.areaMeshes
    }
    const last = this.areaMeshes[this.areaMeshes.length - 1]
    const arr = this.areaMeshes.slice(0, this.areaMeshes.length - 1)
    return createAreasBySubtraction(last.vo, arr.map(it => it.vo))
  }
  attachItem(workAreaMesh) {
    this.detachItem()
    this.areaMeshes.push(workAreaMesh)
    workAreaMesh.toggleSelected(true)
  }

  detachItem(data) {
    if (this.areaMesh) {
      this.areaMesh.toggleSelected(false)
    }
    this.areaMeshes.forEach(it => it.toggleSelected(false))
    this.areaMeshes.length = 0
  }
  removeSelect() {
    if (!this.areaMeshes.length) {
      return
    }
    const arr = this.areaMeshes
    arr.forEach(it => it.removeFromParent())
    arrAsubB(this.world3d.store.areaMeshes, arr)
    arr.length = 0
  }
  changeSelectedAreaColor(colorStr) {
    const selectMesh = this.world3d.store.pickingArea();
    if (!selectMesh) {
      return;
    }
    const color = selectMesh.material.color;
    const old = color.getStyle();
    const ctx = {
      colorRef: color,
      colorOld: '#' + color.getHexString(),
      colorNew: colorStr,
      mesh: selectMesh,
    };
    this.world3d.editRecord.addOrUpdateAction(UndoType.setWorkAreaColor, ctx);
    color.setStyle(colorStr);
    selectMesh.toggleSelected(true);
    if (color.getStyle() !== old) {
      selectMesh.vo.colorCode = mapColorCssToCode.get(colorStr)
      this.world3d.editorContentChanged = true;
    }
  }
  changeSelectedAreaSurfacing(surfacing) {
    const selectMesh = this.world3d.store.pickingArea();
    if (!selectMesh) {
      return;
    }
    selectMesh.vo.fromSurface = surfacing
  }

  pointerDown(event) {
    if (event.button === 2) { // mouse right button down
      return false
    }
    if (this.world3d.store.stateFree) {
      const selectingHole = this.world3d._selectHolePlugin.holeMesh
      if (selectingHole) {
        return false
      }
      const selectArea = this.world3d.store.pickingArea()
      if (selectArea) {
        const arr = this.areaMeshes
        if (KeyboardState.keyDownCtrl) {
          if (!arr.includes(selectArea)) {
            arr.push(selectArea)
          } else {
            selectArea.toggleSelected(false)
            removeArrayItem(arr, selectArea)
          }
          if (arr.length) {
            arr.forEach((it, index) => it.toggleSelected(true, index === arr.length - 1 && arr.length > 1))
          }
        } else {
          this.attachItem(selectArea)
          const event = World3dEvent.workAreaSelected
          event.value.color = '#' + selectArea.material.color.getHexString()
          event.value.areaName = selectArea.vo.name
          event.value.fromSurface = selectArea.vo.fromSurface
          this.world3d.scene.dispatchEvent(event)
        }
        axesHelper.position.copy(selectArea.vo.getCenterInWorld());
        matRot.extractRotation(selectArea.vo.planeMat);
        axesHelper.rotation.setFromRotationMatrix(matRot);
        this.world3d.scene.add(axesHelper);
      }
    }
  }
}
